home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / usenet / volume4 / chtrans < prev    next >
Encoding:
Text File  |  1988-06-07  |  59.8 KB  |  2,383 lines

  1. Path: uunet!tektronix!tekgen!tekred!games
  2. From: games@tekred.TEK.COM
  3. Newsgroups: comp.sources.games
  4. Subject: v04i031:  chtrans - a chess notation translator (standard to Cartesian algebraic)
  5. Message-ID: <2613@tekred.TEK.COM>
  6. Date: 7 Jun 88 23:09:52 GMT
  7. Sender: billr@tekred.TEK.COM
  8. Lines: 2372
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted by: Ray Balogh <rabalogh@ccng.waterloo.edu>
  12. Comp.sources.games: Volume 4, Issue 31
  13. Archive-name: chtrans
  14.  
  15.     [See also, previous posting for displaying moves on a vt240
  16.      using ReGIS graphics.  -br]
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of shell archive."
  25. # Contents:  README Makefile chtrans.c regerror.c regexp.c regexp.h
  26. #   regmagic.h trmoves.c
  27. # Wrapped by billr@saab on Tue Jun  7 16:08:00 1988
  28. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  29. if test -f README -a "${1}" != "-c" ; then 
  30.   echo shar: Will not over-write existing file \"README\"
  31. else
  32. echo shar: Extracting \"README\" \(1679 characters\)
  33. sed "s/^X//" >README <<'END_OF_README'
  34. X
  35. XChtrans
  36. X-------
  37. X
  38. X  SYNOPSIS:  chtrans
  39. X
  40. X  DESCRIPTION:
  41. X
  42. X     A filter for translating standard algebraic chess notation (e.g., d:c)
  43. X     to Cartesian algebraic (e.g., d5c4).  It read from the standard input
  44. X     and writes to the standard output only.  It is based on a regualar
  45. X     expression package (similar to regex(3)) written by Henry Spencer
  46. X     at the University of Toronto (only the portion of the package needed
  47. X     for chtrans is included), and on legal move generation code
  48. X     derived from John Stanback's chess program.
  49. X
  50. X     The input is treated as "words" (blank delimited tokens), and any word
  51. X     that is not entirely a syntactically correct move is discarded.
  52. X     Commented text i.e. (...) or #...<newline> is ignored (the opening
  53. X     character must be separated from the end of the preceding move by
  54. X     white space).  Parenthesized comments nest, and a '(' need not be
  55. X     matched by a ')' -- the remainder of the file will be ignored.
  56. X
  57. X     Verbose diagnostics are printed on illegal moves, if the program
  58. X     is compiled with the -DVERBOSE option.
  59. X
  60. X     Before piping the output of this program to anything, run it alone
  61. X     to make sure the input is translated without error.
  62. X
  63. X  SUGGESTIONS:
  64. X
  65. X     The verbose diagnostic feature should be a command line option.
  66. X
  67. X     Other types of translations should be supported.
  68. X
  69. X  BUGS:
  70. X
  71. X     Was written without any kind of published standard or precisely
  72. X     defined grammar, so some forms such as "de:" are not understood.
  73. X
  74. X     Commented text should not have to be separated from the preceding
  75. X     word by white space.  The same is true for the move numbers,
  76. X     i.e., "1.e2e4" should be accepted.
  77. END_OF_README
  78. if test 1679 -ne `wc -c <README`; then
  79.     echo shar: \"README\" unpacked with wrong size!
  80. fi
  81. # end of overwriting check
  82. fi
  83. if test -f Makefile -a "${1}" != "-c" ; then 
  84.   echo shar: Will not over-write existing file \"Makefile\"
  85. else
  86. echo shar: Extracting \"Makefile\" \(345 characters\)
  87. sed "s/^X//" >Makefile <<'END_OF_Makefile'
  88. X# Makefile for chtrans (notation translator)
  89. X
  90. XT_FLAGS = -DBSD -DVERBOSE
  91. XT_OBJ   = chtrans.o trmoves.o
  92. XT_INC   = regexp.h
  93. XTLIB_OBJ   = regexp.o regerror.o
  94. XTLIB_INC   = regexp.h regmagic.h
  95. X
  96. X####
  97. X
  98. Xall: chtrans $(TLIB_OBJ)
  99. X
  100. Xchtrans: $(T_OBJ) $(TLIB_OBJ)
  101. X    cc -o chtrans $(T_FLAGS) $(T_OBJ) $(TLIB_OBJ)
  102. X
  103. X$(T_OBJ):   $(T_INC)
  104. X$(TLIB_OBJ): $(TLIB_INC)
  105. X
  106. END_OF_Makefile
  107. if test 345 -ne `wc -c <Makefile`; then
  108.     echo shar: \"Makefile\" unpacked with wrong size!
  109. fi
  110. # end of overwriting check
  111. fi
  112. if test -f chtrans.c -a "${1}" != "-c" ; then 
  113.   echo shar: Will not over-write existing file \"chtrans.c\"
  114. else
  115. echo shar: Extracting \"chtrans.c\" \(4003 characters\)
  116. sed "s/^X//" >chtrans.c <<'END_OF_chtrans.c'
  117. X/*
  118. X *    Copyright (c) 1987 by Ray Balogh (rabalogh@ccng.waterloo.edu)
  119. X *
  120. X *    Permission is granted to anyone to use this software for any
  121. X *    purpose on any computer system, and to redistribute it freely,
  122. X *    subject to the following restrictions:
  123. X *
  124. X *    1. The author is not responsible for the consequences of use of
  125. X *    this software, no matter how awful, even if they arise
  126. X *    from defects in it.
  127. X *
  128. X *    2. The origin of this software must not be misrepresented, either
  129. X *    by explicit claim or by omission.
  130. X *
  131. X *    3. Altered versions must be plainly marked as such, and must not
  132. X *    be misrepresented as being the original software.
  133. X *
  134. X */
  135. X
  136. X/* see "regexp.c" for the copyright notice pertaining to the regular
  137. X * expression parser.
  138. X */
  139. X
  140. X#include <stdio.h>
  141. X#include "regexp.h"
  142. X
  143. X#define DUNNO    '_'
  144. X
  145. Xchar buf[20];
  146. X
  147. Xchar gram1_castle[] =
  148. X  "^[oO0]-[oO0](-[oO0])?(ch|mt|[+])?[!?,.;]*$";
  149. Xchar gram1_general[] =
  150. X  "^([NBRQK]?)([a-h]?)([1-8]?)([xX:-]?)([a-h]?)([1-8]?)(ch|mt|[+])?[!?,.;]*$";
  151. Xchar gram1_ignore[] =
  152. X"^([0-9]+\\.?|a|be|each|he|ch|mt|Re:)$";
  153. X
  154. X#define SUBEX(p,i)    (p->startp[i])
  155. X#define NILSUBEX(p,i)    (p->endp[i] == p->startp[i])
  156. X#define SUBEXLEN(p,i)    (p->endp[i] - p->startp[i])
  157. X#define BDCHAR(p,i)    ((!NILSUBEX(p,i)) ? *SUBEX(p,i) : DUNNO)
  158. X
  159. X
  160. X/* gobble (possibly nested) comments */
  161. Xgobble( s, openc, closec )
  162. Xchar *s, openc, closec;
  163. X{
  164. X    int c;
  165. X
  166. X    while ( *++s != '\0' )
  167. X    if ( *s == openc )
  168. X        gobble( s, openc, closec );
  169. X    else if ( *s == closec )
  170. X        return;
  171. X    while ( (c = getchar()) != EOF && c != (int)closec )
  172. X    if ( c == (int)openc )
  173. X        gobble( " ", openc, closec );
  174. X}
  175. X
  176. X
  177. X/* check if s contains any valid move spec. char */
  178. Xint
  179. Xtestmove( s )
  180. Xchar *s;
  181. X{
  182. X    static int testtab[128] = {
  183. X      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  184. X      0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,-1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
  185. X      0,0,50,0,0,0,0,0,0,0,0,50,0,0,50,-1,0,50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,
  186. X      0,50,50,50,50,50,50,50,50,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  187. X    };
  188. X    register int sum;
  189. X    register char *p;
  190. X
  191. X    for ( sum = 0, p = s; *p != '\0' ; p++ )
  192. X    sum += testtab[ (int)*p & 0xFF ];
  193. X    return ( sum > 50 || sum < -2 );
  194. X}
  195. X
  196. X
  197. X/* ARGSUSED */
  198. Xmain(argc, argv)
  199. Xint argc;
  200. Xchar *argv[];
  201. X{
  202. X    regexp *g1_ignore, *g1_castle, *g1_general, *expr;
  203. X    int i,j;
  204. X    char piece, sep, f1, r1, f2, r2;
  205. X    char s[256];
  206. X    static int ply = 0;
  207. X
  208. X    if ( (g1_ignore = regcomp(gram1_ignore)) == NULL ||
  209. X     (g1_castle =  regcomp(gram1_castle)) == NULL ||
  210. X     (g1_general = regcomp(gram1_general)) == NULL ) {
  211. X    fprintf( stderr, "bad grammar\n" );
  212. X    exit(1);
  213. X    }
  214. X
  215. X    while ( scanf("%s",s) == 1 ) {
  216. X
  217. X    /* gobble comments */
  218. X    if ( *s == '#' ) {
  219. X        gobble( s, '\0', '\n' );
  220. X        continue;
  221. X    }
  222. X    if ( *s == '(' ) {
  223. X        gobble( s, '(', ')' );
  224. X        continue;
  225. X    }
  226. X    /* DEBUG fprintf( stderr, "[%s] ", s ); */
  227. X
  228. X    if ( ! testmove(s) )    /* make cursory validity check */
  229. X        continue;
  230. X
  231. X    if ( regexec(g1_ignore, s) == 1 ) {
  232. X        continue;
  233. X    } else
  234. X    if ( regexec(g1_castle, s) == 1 ) {
  235. X        expr = g1_castle;
  236. X        if ( expr->startp[1] == expr->endp[1] )    /* king's side */
  237. X        {sprintf( buf, "Ke%c-g%c", DUNNO, DUNNO ); trans(buf, ++ply);}
  238. X        else
  239. X        {sprintf( buf, "Ke%c-c%c", DUNNO, DUNNO ); trans(buf, ++ply);}
  240. X        continue;
  241. X    } else
  242. X    if ( regexec(g1_general, s) == 1 ) {
  243. X        expr = g1_general;
  244. X        piece = BDCHAR(expr,1);
  245. X        f1 = BDCHAR(expr,2); r1 = BDCHAR(expr,3);
  246. X        f2 = BDCHAR(expr,5); r2 = BDCHAR(expr,6);
  247. X        sep = BDCHAR(expr,4);
  248. X
  249. X        if ( f2 == DUNNO && r2 == DUNNO ) {
  250. X        f2 = f1; r2 = r1;
  251. X        f1 = DUNNO; r1 = DUNNO;
  252. X        }
  253. X        if ( piece == DUNNO )
  254. X        piece = 'P';
  255. X        /*            if sep is not given, leave it as unspecified
  256. X        if ( sep == DUNNO )
  257. X        sep = '-';
  258. X        */
  259. X        if (sep != '-' && sep != DUNNO)
  260. X        sep = ':';
  261. X        sprintf( buf, "%c%c%c%c%c%c%.*s",
  262. X        piece, f1, r1, sep, f2, r2, SUBEXLEN(expr,7), SUBEX(expr,7) );
  263. X        trans(buf, ++ply);
  264. X        continue;
  265. X    } else {
  266. X        /* fprintf( stderr, "syntax error\n" ); */
  267. X        continue;
  268. X    }
  269. X    }
  270. X    exit(0);
  271. X}
  272. END_OF_chtrans.c
  273. if test 4003 -ne `wc -c <chtrans.c`; then
  274.     echo shar: \"chtrans.c\" unpacked with wrong size!
  275. fi
  276. # end of overwriting check
  277. fi
  278. if test -f regerror.c -a "${1}" != "-c" ; then 
  279.   echo shar: Will not over-write existing file \"regerror.c\"
  280. else
  281. echo shar: Extracting \"regerror.c\" \(224 characters\)
  282. sed "s/^X//" >regerror.c <<'END_OF_regerror.c'
  283. X#include <stdio.h>
  284. X
  285. Xvoid
  286. Xregerror(s)
  287. Xchar *s;
  288. X{
  289. X#ifdef ERRAVAIL
  290. X    error("regexp: %s", s);
  291. X#else
  292. X/*
  293. X    fprintf(stderr, "regexp(3): %s\n", s);
  294. X    exit(1);
  295. X*/
  296. X    return;      /* let std. egrep handle errors */
  297. X#endif
  298. X    /* NOTREACHED */
  299. X}
  300. END_OF_regerror.c
  301. if test 224 -ne `wc -c <regerror.c`; then
  302.     echo shar: \"regerror.c\" unpacked with wrong size!
  303. fi
  304. # end of overwriting check
  305. fi
  306. if test -f regexp.c -a "${1}" != "-c" ; then 
  307.   echo shar: Will not over-write existing file \"regexp.c\"
  308. else
  309. echo shar: Extracting \"regexp.c\" \(27784 characters\)
  310. sed "s/^X//" >regexp.c <<'END_OF_regexp.c'
  311. X/*
  312. X * regcomp and regexec -- regsub and regerror are elsewhere
  313. X *
  314. X *    Copyright (c) 1986 by University of Toronto.
  315. X *    Written by Henry Spencer.  Not derived from licensed software.
  316. X *
  317. X *    Permission is granted to anyone to use this software for any
  318. X *    purpose on any computer system, and to redistribute it freely,
  319. X *    subject to the following restrictions:
  320. X *
  321. X *    1. The author is not responsible for the consequences of use of
  322. X *        this software, no matter how awful, even if they arise
  323. X *        from defects in it.
  324. X *
  325. X *    2. The origin of this software must not be misrepresented, either
  326. X *        by explicit claim or by omission.
  327. X *
  328. X *    3. Altered versions must be plainly marked as such, and must not
  329. X *        be misrepresented as being the original software.
  330. X *
  331. X * Beware that some of this code is subtly aware of the way operator
  332. X * precedence is structured in regular expressions.  Serious changes in
  333. X * regular-expression syntax might require a total rethink.
  334. X */
  335. X#include <stdio.h>
  336. X#include "regexp.h"
  337. X#include "regmagic.h"
  338. X
  339. X/*
  340. X * The "internal use only" fields in regexp.h are present to pass info from
  341. X * compile to execute that permits the execute phase to run lots faster on
  342. X * simple cases.  They are:
  343. X *
  344. X * regstart    char that must begin a match; '\0' if none obvious
  345. X * reganch    is the match anchored (at beginning-of-line only)?
  346. X * regmust    string (pointer into program) that match must include, or NULL
  347. X * regmlen    length of regmust string
  348. X *
  349. X * Regstart and reganch permit very fast decisions on suitable starting points
  350. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  351. X * of lines that cannot possibly match.  The regmust tests are costly enough
  352. X * that regcomp() supplies a regmust only if the r.e. contains something
  353. X * potentially expensive (at present, the only such thing detected is * or +
  354. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  355. X * supplied because the test in regexec() needs it and regcomp() is computing
  356. X * it anyway.
  357. X */
  358. X
  359. X/*
  360. X * Structure for regexp "program".  This is essentially a linear encoding
  361. X * of a nondeterministic finite-state machine (aka syntax charts or
  362. X * "railroad normal form" in parsing technology).  Each node is an opcode
  363. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  364. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  365. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  366. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  367. X * opposed to a collection of them) is never concatenated with anything
  368. X * because of operator precedence.)  The operand of some types of node is
  369. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  370. X * particular, the operand of a BRANCH node is the first node of the branch.
  371. X * (NB this is *not* a tree structure:  the tail of the branch connects
  372. X * to the thing following the set of BRANCHes.)  The opcodes are:
  373. X */
  374. X
  375. X/* definition    number    opnd?    meaning */
  376. X#define    END    0    /* no    End of program. */
  377. X#define    BOL    1    /* no    Match "" at beginning of line. */
  378. X#define    EOL    2    /* no    Match "" at end of line. */
  379. X#define    ANY    3    /* no    Match any one character. */
  380. X#define    ANYOF    4    /* str    Match any character in this string. */
  381. X#define    ANYBUT    5    /* str    Match any character not in this string. */
  382. X#define    BRANCH    6    /* node    Match this alternative, or the next... */
  383. X#define    BACK    7    /* no    Match "", "next" ptr points backward. */
  384. X#define    EXACTLY    8    /* str    Match this string. */
  385. X#define    NOTHING    9    /* no    Match empty string. */
  386. X#define    STAR    10    /* node    Match this (simple) thing 0 or more times. */
  387. X#define    PLUS    11    /* node    Match this (simple) thing 1 or more times. */
  388. X#define    OPEN    20    /* no    Mark this point in input as start of #n. */
  389. X            /*    OPEN+1 is number 1, etc. */
  390. X#define    CLOSE    30    /* no    Analogous to OPEN. */
  391. X
  392. X/*
  393. X * Opcode notes:
  394. X *
  395. X * BRANCH    The set of branches constituting a single choice are hooked
  396. X *        together with their "next" pointers, since precedence prevents
  397. X *        anything being concatenated to any individual branch.  The
  398. X *        "next" pointer of the last BRANCH in a choice points to the
  399. X *        thing following the whole choice.  This is also where the
  400. X *        final "next" pointer of each individual branch points; each
  401. X *        branch starts with the operand node of a BRANCH node.
  402. X *
  403. X * BACK        Normal "next" pointers all implicitly point forward; BACK
  404. X *        exists to make loop structures possible.
  405. X *
  406. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  407. X *        BRANCH structures using BACK.  Simple cases (one character
  408. X *        per match) are implemented with STAR and PLUS for speed
  409. X *        and to minimize recursive plunges.
  410. X *
  411. X * OPEN,CLOSE    ...are numbered at compile time.
  412. X */
  413. X
  414. X/*
  415. X * A node is one char of opcode followed by two chars of "next" pointer.
  416. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  417. X * value is a positive offset from the opcode of the node containing it.
  418. X * An operand, if any, simply follows the node.  (Note that much of the
  419. X * code generation knows about this implicit relationship.)
  420. X *
  421. X * Using two bytes for the "next" pointer is vast overkill for most things,
  422. X * but allows patterns to get big without disasters.
  423. X */
  424. X#define    OP(p)    (*(p))
  425. X#define    NEXT(p)    (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
  426. X#define    OPERAND(p)    ((p) + 3)
  427. X
  428. X/*
  429. X * See regmagic.h for one further detail of program structure.
  430. X */
  431. X
  432. X
  433. X/*
  434. X * Utility definitions.
  435. X */
  436. X#ifndef CHARBITS
  437. X#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  438. X#else
  439. X#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  440. X#endif
  441. X
  442. X#define    FAIL(m)    { regerror(m); return(NULL); }
  443. X#define    ISMULT(c)    ((c) == '*' || (c) == '+' || (c) == '?')
  444. X#define    META    "^$.[()|?+*\\"
  445. X
  446. X/*
  447. X * Flags to be passed up and down.
  448. X */
  449. X#define    HASWIDTH    01    /* Known never to match null string. */
  450. X#define    SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  451. X#define    SPSTART        04    /* Starts with * or +. */
  452. X#define    WORST        0    /* Worst case. */
  453. X
  454. X/*
  455. X * Global work variables for regcomp().
  456. X */
  457. Xstatic char *regparse;        /* Input-scan pointer. */
  458. Xstatic int regnpar;        /* () count. */
  459. Xstatic char regdummy;
  460. Xstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  461. Xstatic long regsize;        /* Code size. */
  462. X
  463. X/*
  464. X * Forward declarations for regcomp()'s friends.
  465. X */
  466. X#ifndef STATIC
  467. X#define    STATIC    static
  468. X#endif
  469. XSTATIC char *reg();
  470. XSTATIC char *regbranch();
  471. XSTATIC char *regpiece();
  472. XSTATIC char *regatom();
  473. XSTATIC char *regnode();
  474. XSTATIC char *regnext();
  475. XSTATIC void regc();
  476. XSTATIC void reginsert();
  477. XSTATIC void regtail();
  478. XSTATIC void regoptail();
  479. X#ifdef STRCSPN
  480. XSTATIC int strcspn();
  481. X#endif
  482. X
  483. X/*
  484. X - regcomp - compile a regular expression into internal code
  485. X *
  486. X * We can't allocate space until we know how big the compiled form will be,
  487. X * but we can't compile it (and thus know how big it is) until we've got a
  488. X * place to put the code.  So we cheat:  we compile it twice, once with code
  489. X * generation turned off and size counting turned on, and once "for real".
  490. X * This also means that we don't allocate space until we are sure that the
  491. X * thing really will compile successfully, and we never have to move the
  492. X * code and thus invalidate pointers into it.  (Note that it has to be in
  493. X * one piece because free() must be able to free it all.)
  494. X *
  495. X * Beware that the optimization-preparation code in here knows about some
  496. X * of the structure of the compiled regexp.
  497. X */
  498. Xregexp *
  499. Xregcomp(exp)
  500. Xchar *exp;
  501. X{
  502. X    register regexp *r;
  503. X    register char *scan;
  504. X    register char *longest;
  505. X    register int len;
  506. X    int flags;
  507. X    extern char *malloc();
  508. X
  509. X    if (exp == NULL)
  510. X        FAIL("NULL argument");
  511. X
  512. X    /* First pass: determine size, legality. */
  513. X    regparse = exp;
  514. X    regnpar = 1;
  515. X    regsize = 0L;
  516. X    regcode = ®dummy;
  517. X    regc(MAGIC);
  518. X    if (reg(0, &flags) == NULL)
  519. X        return(NULL);
  520. X
  521. X    /* Small enough for pointer-storage convention? */
  522. X    if (regsize >= 32767L)        /* Probably could be 65535L. */
  523. X        FAIL("regexp too big");
  524. X
  525. X    /* Allocate space. */
  526. X    r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
  527. X    if (r == NULL)
  528. X        FAIL("out of space");
  529. X
  530. X    /* Second pass: emit code. */
  531. X    regparse = exp;
  532. X    regnpar = 1;
  533. X    regcode = r->program;
  534. X    regc(MAGIC);
  535. X    if (reg(0, &flags) == NULL)
  536. X        return(NULL);
  537. X
  538. X    /* Dig out information for optimizations. */
  539. X    r->regstart = '\0';    /* Worst-case defaults. */
  540. X    r->reganch = 0;
  541. X    r->regmust = NULL;
  542. X    r->regmlen = 0;
  543. X    scan = r->program+1;            /* First BRANCH. */
  544. X    if (OP(regnext(scan)) == END) {        /* Only one top-level choice. */
  545. X        scan = OPERAND(scan);
  546. X
  547. X        /* Starting-point info. */
  548. X        if (OP(scan) == EXACTLY)
  549. X            r->regstart = *OPERAND(scan);
  550. X        else if (OP(scan) == BOL)
  551. X            r->reganch++;
  552. X
  553. X        /*
  554. X         * If there's something expensive in the r.e., find the
  555. X         * longest literal string that must appear and make it the
  556. X         * regmust.  Resolve ties in favor of later strings, since
  557. X         * the regstart check works with the beginning of the r.e.
  558. X         * and avoiding duplication strengthens checking.  Not a
  559. X         * strong reason, but sufficient in the absence of others.
  560. X         */
  561. X        if (flags&SPSTART) {
  562. X            longest = NULL;
  563. X            len = 0;
  564. X            for (; scan != NULL; scan = regnext(scan))
  565. X                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  566. X                    longest = OPERAND(scan);
  567. X                    len = strlen(OPERAND(scan));
  568. X                }
  569. X            r->regmust = longest;
  570. X            r->regmlen = len;
  571. X        }
  572. X    }
  573. X
  574. X    return(r);
  575. X}
  576. X
  577. X/*
  578. X - reg - regular expression, i.e. main body or parenthesized thing
  579. X *
  580. X * Caller must absorb opening parenthesis.
  581. X *
  582. X * Combining parenthesis handling with the base level of regular expression
  583. X * is a trifle forced, but the need to tie the tails of the branches to what
  584. X * follows makes it hard to avoid.
  585. X */
  586. Xstatic char *
  587. Xreg(paren, flagp)
  588. Xint paren;            /* Parenthesized? */
  589. Xint *flagp;
  590. X{
  591. X    register char *ret;
  592. X    register char *br;
  593. X    register char *ender;
  594. X    register int parno;
  595. X    int flags;
  596. X
  597. X    *flagp = HASWIDTH;    /* Tentatively. */
  598. X
  599. X    /* Make an OPEN node, if parenthesized. */
  600. X    if (paren) {
  601. X        if (regnpar >= NSUBEXP)
  602. X            FAIL("too many ()");
  603. X        parno = regnpar;
  604. X        regnpar++;
  605. X        ret = regnode(OPEN+parno);
  606. X    } else
  607. X        ret = NULL;
  608. X
  609. X    /* Pick up the branches, linking them together. */
  610. X    br = regbranch(&flags);
  611. X    if (br == NULL)
  612. X        return(NULL);
  613. X    if (ret != NULL)
  614. X        regtail(ret, br);    /* OPEN -> first. */
  615. X    else
  616. X        ret = br;
  617. X    if (!(flags&HASWIDTH))
  618. X        *flagp &= ~HASWIDTH;
  619. X    *flagp |= flags&SPSTART;
  620. X    while (*regparse == '|') {
  621. X        regparse++;
  622. X        br = regbranch(&flags);
  623. X        if (br == NULL)
  624. X            return(NULL);
  625. X        regtail(ret, br);    /* BRANCH -> BRANCH. */
  626. X        if (!(flags&HASWIDTH))
  627. X            *flagp &= ~HASWIDTH;
  628. X        *flagp |= flags&SPSTART;
  629. X    }
  630. X
  631. X    /* Make a closing node, and hook it on the end. */
  632. X    ender = regnode((paren) ? CLOSE+parno : END);    
  633. X    regtail(ret, ender);
  634. X
  635. X    /* Hook the tails of the branches to the closing node. */
  636. X    for (br = ret; br != NULL; br = regnext(br))
  637. X        regoptail(br, ender);
  638. X
  639. X    /* Check for proper termination. */
  640. X    if (paren && *regparse++ != ')') {
  641. X        FAIL("unmatched ()");
  642. X    } else if (!paren && *regparse != '\0') {
  643. X        if (*regparse == ')') {
  644. X            FAIL("unmatched ()");
  645. X        } else
  646. X            FAIL("junk on end");    /* "Can't happen". */
  647. X        /* NOTREACHED */
  648. X    }
  649. X
  650. X    return(ret);
  651. X}
  652. X
  653. X/*
  654. X - regbranch - one alternative of an | operator
  655. X *
  656. X * Implements the concatenation operator.
  657. X */
  658. Xstatic char *
  659. Xregbranch(flagp)
  660. Xint *flagp;
  661. X{
  662. X    register char *ret;
  663. X    register char *chain;
  664. X    register char *latest;
  665. X    int flags;
  666. X
  667. X    *flagp = WORST;        /* Tentatively. */
  668. X
  669. X    ret = regnode(BRANCH);
  670. X    chain = NULL;
  671. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  672. X        latest = regpiece(&flags);
  673. X        if (latest == NULL)
  674. X            return(NULL);
  675. X        *flagp |= flags&HASWIDTH;
  676. X        if (chain == NULL)    /* First piece. */
  677. X            *flagp |= flags&SPSTART;
  678. X        else
  679. X            regtail(chain, latest);
  680. X        chain = latest;
  681. X    }
  682. X    if (chain == NULL)    /* Loop ran zero times. */
  683. X        (void) regnode(NOTHING);
  684. X
  685. X    return(ret);
  686. X}
  687. X
  688. X/*
  689. X - regpiece - something followed by possible [*+?]
  690. X *
  691. X * Note that the branching code sequences used for ? and the general cases
  692. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  693. X * both the endmarker for their branch list and the body of the last branch.
  694. X * It might seem that this node could be dispensed with entirely, but the
  695. X * endmarker role is not redundant.
  696. X */
  697. Xstatic char *
  698. Xregpiece(flagp)
  699. Xint *flagp;
  700. X{
  701. X    register char *ret;
  702. X    register char op;
  703. X    register char *next;
  704. X    int flags;
  705. X
  706. X    ret = regatom(&flags);
  707. X    if (ret == NULL)
  708. X        return(NULL);
  709. X
  710. X    op = *regparse;
  711. X    if (!ISMULT(op)) {
  712. X        *flagp = flags;
  713. X        return(ret);
  714. X    }
  715. X
  716. X    if (!(flags&HASWIDTH) && op != '?')
  717. X        FAIL("*+ operand could be empty");
  718. X    *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  719. X
  720. X    if (op == '*' && (flags&SIMPLE))
  721. X        reginsert(STAR, ret);
  722. X    else if (op == '*') {
  723. X        /* Emit x* as (x&|), where & means "self". */
  724. X        reginsert(BRANCH, ret);            /* Either x */
  725. X        regoptail(ret, regnode(BACK));        /* and loop */
  726. X        regoptail(ret, ret);            /* back */
  727. X        regtail(ret, regnode(BRANCH));        /* or */
  728. X        regtail(ret, regnode(NOTHING));        /* null. */
  729. X    } else if (op == '+' && (flags&SIMPLE))
  730. X        reginsert(PLUS, ret);
  731. X    else if (op == '+') {
  732. X        /* Emit x+ as x(&|), where & means "self". */
  733. X        next = regnode(BRANCH);            /* Either */
  734. X        regtail(ret, next);
  735. X        regtail(regnode(BACK), ret);        /* loop back */
  736. X        regtail(next, regnode(BRANCH));        /* or */
  737. X        regtail(ret, regnode(NOTHING));        /* null. */
  738. X    } else if (op == '?') {
  739. X        /* Emit x? as (x|) */
  740. X        reginsert(BRANCH, ret);            /* Either x */
  741. X        regtail(ret, regnode(BRANCH));        /* or */
  742. X        next = regnode(NOTHING);        /* null. */
  743. X        regtail(ret, next);
  744. X        regoptail(ret, next);
  745. X    }
  746. X    regparse++;
  747. X    if (ISMULT(*regparse))
  748. X        FAIL("nested *?+");
  749. X
  750. X    return(ret);
  751. X}
  752. X
  753. X/*
  754. X - regatom - the lowest level
  755. X *
  756. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  757. X * it can turn them into a single node, which is smaller to store and
  758. X * faster to run.  Backslashed characters are exceptions, each becoming a
  759. X * separate node; the code is simpler that way and it's not worth fixing.
  760. X */
  761. Xstatic char *
  762. Xregatom(flagp)
  763. Xint *flagp;
  764. X{
  765. X    register char *ret;
  766. X    int flags;
  767. X
  768. X    *flagp = WORST;        /* Tentatively. */
  769. X
  770. X    switch (*regparse++) {
  771. X    case '^':
  772. X        ret = regnode(BOL);
  773. X        break;
  774. X    case '$':
  775. X        ret = regnode(EOL);
  776. X        break;
  777. X    case '.':
  778. X        ret = regnode(ANY);
  779. X        *flagp |= HASWIDTH|SIMPLE;
  780. X        break;
  781. X    case '[': {
  782. X            register int class;
  783. X            register int classend;
  784. X
  785. X            if (*regparse == '^') {    /* Complement of range. */
  786. X                ret = regnode(ANYBUT);
  787. X                regparse++;
  788. X            } else
  789. X                ret = regnode(ANYOF);
  790. X            if (*regparse == ']' || *regparse == '-')
  791. X                regc(*regparse++);
  792. X            while (*regparse != '\0' && *regparse != ']') {
  793. X                if (*regparse == '-') {
  794. X                    regparse++;
  795. X                    if (*regparse == ']' || *regparse == '\0')
  796. X                        regc('-');
  797. X                    else {
  798. X                        class = UCHARAT(regparse-2)+1;
  799. X                        classend = UCHARAT(regparse);
  800. X                        if (class > classend+1)
  801. X                            FAIL("invalid [] range");
  802. X                        for (; class <= classend; class++)
  803. X                            regc(class);
  804. X                        regparse++;
  805. X                    }
  806. X                } else
  807. X                    regc(*regparse++);
  808. X            }
  809. X            regc('\0');
  810. X            if (*regparse != ']')
  811. X                FAIL("unmatched []");
  812. X            regparse++;
  813. X            *flagp |= HASWIDTH|SIMPLE;
  814. X        }
  815. X        break;
  816. X    case '(':
  817. X        ret = reg(1, &flags);
  818. X        if (ret == NULL)
  819. X            return(NULL);
  820. X        *flagp |= flags&(HASWIDTH|SPSTART);
  821. X        break;
  822. X    case '\0':
  823. X    case '|':
  824. X    case ')':
  825. X        FAIL("internal urp");    /* Supposed to be caught earlier. */
  826. X        /* NOTREACHED */
  827. X        /*break;*/
  828. X    case '?':
  829. X    case '+':
  830. X    case '*':
  831. X        FAIL("?+* follows nothing");
  832. X        /* NOTREACHED */
  833. X        /*break;*/
  834. X    case '\\':
  835. X        if (*regparse == '\0')
  836. X            FAIL("trailing \\");
  837. X        ret = regnode(EXACTLY);
  838. X        regc(*regparse++);
  839. X        regc('\0');
  840. X        *flagp |= HASWIDTH|SIMPLE;
  841. X        break;
  842. X    default: {
  843. X            register int len;
  844. X            register char ender;
  845. X
  846. X            regparse--;
  847. X            len = strcspn(regparse, META);
  848. X            if (len <= 0)
  849. X                FAIL("internal disaster");
  850. X            ender = *(regparse+len);
  851. X            if (len > 1 && ISMULT(ender))
  852. X                len--;        /* Back off clear of ?+* operand. */
  853. X            *flagp |= HASWIDTH;
  854. X            if (len == 1)
  855. X                *flagp |= SIMPLE;
  856. X            ret = regnode(EXACTLY);
  857. X            while (len > 0) {
  858. X                regc(*regparse++);
  859. X                len--;
  860. X            }
  861. X            regc('\0');
  862. X        }
  863. X        break;
  864. X    }
  865. X
  866. X    return(ret);
  867. X}
  868. X
  869. X/*
  870. X - regnode - emit a node
  871. X */
  872. Xstatic char *            /* Location. */
  873. Xregnode(op)
  874. Xchar op;
  875. X{
  876. X    register char *ret;
  877. X    register char *ptr;
  878. X
  879. X    ret = regcode;
  880. X    if (ret == ®dummy) {
  881. X        regsize += 3;
  882. X        return(ret);
  883. X    }
  884. X
  885. X    ptr = ret;
  886. X    *ptr++ = op;
  887. X    *ptr++ = '\0';        /* Null "next" pointer. */
  888. X    *ptr++ = '\0';
  889. X    regcode = ptr;
  890. X
  891. X    return(ret);
  892. X}
  893. X
  894. X/*
  895. X - regc - emit (if appropriate) a byte of code
  896. X */
  897. Xstatic void
  898. Xregc(b)
  899. Xchar b;
  900. X{
  901. X    if (regcode != ®dummy)
  902. X        *regcode++ = b;
  903. X    else
  904. X        regsize++;
  905. X}
  906. X
  907. X/*
  908. X - reginsert - insert an operator in front of already-emitted operand
  909. X *
  910. X * Means relocating the operand.
  911. X */
  912. Xstatic void
  913. Xreginsert(op, opnd)
  914. Xchar op;
  915. Xchar *opnd;
  916. X{
  917. X    register char *src;
  918. X    register char *dst;
  919. X    register char *place;
  920. X
  921. X    if (regcode == ®dummy) {
  922. X        regsize += 3;
  923. X        return;
  924. X    }
  925. X
  926. X    src = regcode;
  927. X    regcode += 3;
  928. X    dst = regcode;
  929. X    while (src > opnd)
  930. X        *--dst = *--src;
  931. X
  932. X    place = opnd;        /* Op node, where operand used to be. */
  933. X    *place++ = op;
  934. X    *place++ = '\0';
  935. X    *place++ = '\0';
  936. X}
  937. X
  938. X/*
  939. X - regtail - set the next-pointer at the end of a node chain
  940. X */
  941. Xstatic void
  942. Xregtail(p, val)
  943. Xchar *p;
  944. Xchar *val;
  945. X{
  946. X    register char *scan;
  947. X    register char *temp;
  948. X    register int offset;
  949. X
  950. X    if (p == ®dummy)
  951. X        return;
  952. X
  953. X    /* Find last node. */
  954. X    scan = p;
  955. X    for (;;) {
  956. X        temp = regnext(scan);
  957. X        if (temp == NULL)
  958. X            break;
  959. X        scan = temp;
  960. X    }
  961. X
  962. X    if (OP(scan) == BACK)
  963. X        offset = scan - val;
  964. X    else
  965. X        offset = val - scan;
  966. X    *(scan+1) = (offset>>8)&0377;
  967. X    *(scan+2) = offset&0377;
  968. X}
  969. X
  970. X/*
  971. X - regoptail - regtail on operand of first argument; nop if operandless
  972. X */
  973. Xstatic void
  974. Xregoptail(p, val)
  975. Xchar *p;
  976. Xchar *val;
  977. X{
  978. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  979. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  980. X        return;
  981. X    regtail(OPERAND(p), val);
  982. X}
  983. X
  984. X/*
  985. X * regexec and friends
  986. X */
  987. X
  988. X/*
  989. X * Global work variables for regexec().
  990. X */
  991. Xstatic char *reginput;        /* String-input pointer. */
  992. Xstatic char *regbol;        /* Beginning of input, for ^ check. */
  993. Xstatic char **regstartp;    /* Pointer to startp array. */
  994. Xstatic char **regendp;        /* Ditto for endp. */
  995. X
  996. X/*
  997. X * Forwards.
  998. X */
  999. XSTATIC int regtry();
  1000. XSTATIC int regmatch();
  1001. XSTATIC int regrepeat();
  1002. X
  1003. X#ifdef DEBUG
  1004. Xint regnarrate = 0;
  1005. Xvoid regdump();
  1006. XSTATIC char *regprop();
  1007. X#endif
  1008. X
  1009. X/*
  1010. X - regexec - match a regexp against a string
  1011. X */
  1012. Xint
  1013. Xregexec(prog, string)
  1014. Xregister regexp *prog;
  1015. Xregister char *string;
  1016. X{
  1017. X    register char *s;
  1018. X    extern char *strchr();
  1019. X
  1020. X    /* Be paranoid... */
  1021. X    if (prog == NULL || string == NULL) {
  1022. X        regerror("NULL parameter");
  1023. X        return(0);
  1024. X    }
  1025. X
  1026. X    /* Check validity of program. */
  1027. X    if (UCHARAT(prog->program) != MAGIC) {
  1028. X        regerror("corrupted program");
  1029. X        return(0);
  1030. X    }
  1031. X
  1032. X    /* If there is a "must appear" string, look for it. */
  1033. X    if (prog->regmust != NULL) {
  1034. X        s = string;
  1035. X        while ((s = strchr(s, prog->regmust[0])) != NULL) {
  1036. X            if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  1037. X                break;    /* Found it. */
  1038. X            s++;
  1039. X        }
  1040. X        if (s == NULL)    /* Not present. */
  1041. X            return(0);
  1042. X    }
  1043. X
  1044. X    /* Mark beginning of line for ^ . */
  1045. X    regbol = string;
  1046. X
  1047. X    /* Simplest case:  anchored match need be tried only once. */
  1048. X    if (prog->reganch)
  1049. X        return(regtry(prog, string));
  1050. X
  1051. X    /* Messy cases:  unanchored match. */
  1052. X    s = string;
  1053. X    if (prog->regstart != '\0')
  1054. X        /* We know what char it must start with. */
  1055. X        while ((s = strchr(s, prog->regstart)) != NULL) {
  1056. X            if (regtry(prog, s))
  1057. X                return(1);
  1058. X            s++;
  1059. X        }
  1060. X    else
  1061. X        /* We don't -- general case. */
  1062. X        do {
  1063. X            if (regtry(prog, s))
  1064. X                return(1);
  1065. X        } while (*s++ != '\0');
  1066. X
  1067. X    /* Failure. */
  1068. X    return(0);
  1069. X}
  1070. X
  1071. X/*
  1072. X - regtry - try match at specific point
  1073. X */
  1074. Xstatic int            /* 0 failure, 1 success */
  1075. Xregtry(prog, string)
  1076. Xregexp *prog;
  1077. Xchar *string;
  1078. X{
  1079. X    register int i;
  1080. X    register char **sp;
  1081. X    register char **ep;
  1082. X
  1083. X    reginput = string;
  1084. X    regstartp = prog->startp;
  1085. X    regendp = prog->endp;
  1086. X
  1087. X    sp = prog->startp;
  1088. X    ep = prog->endp;
  1089. X    for (i = NSUBEXP; i > 0; i--) {
  1090. X        *sp++ = NULL;
  1091. X        *ep++ = NULL;
  1092. X    }
  1093. X    if (regmatch(prog->program + 1)) {
  1094. X        prog->startp[0] = string;
  1095. X        prog->endp[0] = reginput;
  1096. X        return(1);
  1097. X    } else
  1098. X        return(0);
  1099. X}
  1100. X
  1101. X/*
  1102. X - regmatch - main matching routine
  1103. X *
  1104. X * Conceptually the strategy is simple:  check to see whether the current
  1105. X * node matches, call self recursively to see whether the rest matches,
  1106. X * and then act accordingly.  In practice we make some effort to avoid
  1107. X * recursion, in particular by going through "ordinary" nodes (that don't
  1108. X * need to know whether the rest of the match failed) by a loop instead of
  1109. X * by recursion.
  1110. X */
  1111. Xstatic int            /* 0 failure, 1 success */
  1112. Xregmatch(prog)
  1113. Xchar *prog;
  1114. X{
  1115. X    register char *scan;    /* Current node. */
  1116. X    char *next;        /* Next node. */
  1117. X    extern char *strchr();
  1118. X
  1119. X    scan = prog;
  1120. X#ifdef DEBUG
  1121. X    if (scan != NULL && regnarrate)
  1122. X        fprintf(stderr, "%s(\n", regprop(scan));
  1123. X#endif
  1124. X    while (scan != NULL) {
  1125. X#ifdef DEBUG
  1126. X        if (regnarrate)
  1127. X            fprintf(stderr, "%s...\n", regprop(scan));
  1128. X#endif
  1129. X        next = regnext(scan);
  1130. X
  1131. X        switch (OP(scan)) {
  1132. X        case BOL:
  1133. X            if (reginput != regbol)
  1134. X                return(0);
  1135. X            break;
  1136. X        case EOL:
  1137. X            if (*reginput != '\0')
  1138. X                return(0);
  1139. X            break;
  1140. X        case ANY:
  1141. X            if (*reginput == '\0')
  1142. X                return(0);
  1143. X            reginput++;
  1144. X            break;
  1145. X        case EXACTLY: {
  1146. X                register int len;
  1147. X                register char *opnd;
  1148. X
  1149. X                opnd = OPERAND(scan);
  1150. X                /* Inline the first character, for speed. */
  1151. X                if (*opnd != *reginput)
  1152. X                    return(0);
  1153. X                len = strlen(opnd);
  1154. X                if (len > 1 && strncmp(opnd, reginput, len) != 0)
  1155. X                    return(0);
  1156. X                reginput += len;
  1157. X            }
  1158. X            break;
  1159. X        case ANYOF:
  1160. X             if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  1161. X                return(0);
  1162. X            reginput++;
  1163. X            break;
  1164. X        case ANYBUT:
  1165. X             if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  1166. X                return(0);
  1167. X            reginput++;
  1168. X            break;
  1169. X        case NOTHING:
  1170. X            break;
  1171. X        case BACK:
  1172. X            break;
  1173. X        case OPEN+1:
  1174. X        case OPEN+2:
  1175. X        case OPEN+3:
  1176. X        case OPEN+4:
  1177. X        case OPEN+5:
  1178. X        case OPEN+6:
  1179. X        case OPEN+7:
  1180. X        case OPEN+8:
  1181. X        case OPEN+9: {
  1182. X                register int no;
  1183. X                register char *save;
  1184. X
  1185. X                no = OP(scan) - OPEN;
  1186. X                save = reginput;
  1187. X
  1188. X                if (regmatch(next)) {
  1189. X                    /*
  1190. X                     * Don't set startp if some later
  1191. X                     * invocation of the same parentheses
  1192. X                     * already has.
  1193. X                     */
  1194. X                    if (regstartp[no] == NULL)
  1195. X                        regstartp[no] = save;
  1196. X                    return(1);
  1197. X                } else
  1198. X                    return(0);
  1199. X            }
  1200. X            /* NOTREACHED */
  1201. X            /*break;*/
  1202. X        case CLOSE+1:
  1203. X        case CLOSE+2:
  1204. X        case CLOSE+3:
  1205. X        case CLOSE+4:
  1206. X        case CLOSE+5:
  1207. X        case CLOSE+6:
  1208. X        case CLOSE+7:
  1209. X        case CLOSE+8:
  1210. X        case CLOSE+9: {
  1211. X                register int no;
  1212. X                register char *save;
  1213. X
  1214. X                no = OP(scan) - CLOSE;
  1215. X                save = reginput;
  1216. X
  1217. X                if (regmatch(next)) {
  1218. X                    /*
  1219. X                     * Don't set endp if some later
  1220. X                     * invocation of the same parentheses
  1221. X                     * already has.
  1222. X                     */
  1223. X                    if (regendp[no] == NULL)
  1224. X                        regendp[no] = save;
  1225. X                    return(1);
  1226. X                } else
  1227. X                    return(0);
  1228. X            }
  1229. X            /* NOTREACHED */
  1230. X            /*break;*/
  1231. X        case BRANCH: {
  1232. X                register char *save;
  1233. X
  1234. X                if (OP(next) != BRANCH)        /* No choice. */
  1235. X                    next = OPERAND(scan);    /* Avoid recursion. */
  1236. X                else {
  1237. X                    do {
  1238. X                        save = reginput;
  1239. X                        if (regmatch(OPERAND(scan)))
  1240. X                            return(1);
  1241. X                        reginput = save;
  1242. X                        scan = regnext(scan);
  1243. X                    } while (scan != NULL && OP(scan) == BRANCH);
  1244. X                    return(0);
  1245. X                    /* NOTREACHED */
  1246. X                }
  1247. X            }
  1248. X            break;
  1249. X        case STAR:
  1250. X        case PLUS: {
  1251. X                register char nextch;
  1252. X                register int no;
  1253. X                register char *save;
  1254. X                register int min;
  1255. X
  1256. X                /*
  1257. X                 * Lookahead to avoid useless match attempts
  1258. X                 * when we know what character comes next.
  1259. X                 */
  1260. X                nextch = '\0';
  1261. X                if (OP(next) == EXACTLY)
  1262. X                    nextch = *OPERAND(next);
  1263. X                min = (OP(scan) == STAR) ? 0 : 1;
  1264. X                save = reginput;
  1265. X                no = regrepeat(OPERAND(scan));
  1266. X                while (no >= min) {
  1267. X                    /* If it could work, try it. */
  1268. X                    if (nextch == '\0' || *reginput == nextch)
  1269. X                        if (regmatch(next))
  1270. X                            return(1);
  1271. X                    /* Couldn't or didn't -- back up. */
  1272. X                    no--;
  1273. X                    reginput = save + no;
  1274. X                }
  1275. X                return(0);
  1276. X            }
  1277. X            /* NOTREACHED */
  1278. X            /*break;*/
  1279. X        case END:
  1280. X            return(1);    /* Success! */
  1281. X            /* NOTREACHED */
  1282. X            /*break;*/
  1283. X        default:
  1284. X            regerror("memory corruption");
  1285. X            return(0);
  1286. X            /* NOTREACHED */
  1287. X            /*break;*/
  1288. X        }
  1289. X
  1290. X        scan = next;
  1291. X    }
  1292. X
  1293. X    /*
  1294. X     * We get here only if there's trouble -- normally "case END" is
  1295. X     * the terminating point.
  1296. X     */
  1297. X    regerror("corrupted pointers");
  1298. X    return(0);
  1299. X}
  1300. X
  1301. X/*
  1302. X - regrepeat - repeatedly match something simple, report how many
  1303. X */
  1304. Xstatic int
  1305. Xregrepeat(p)
  1306. Xchar *p;
  1307. X{
  1308. X    register int count = 0;
  1309. X    register char *scan;
  1310. X    register char *opnd;
  1311. X
  1312. X    scan = reginput;
  1313. X    opnd = OPERAND(p);
  1314. X    switch (OP(p)) {
  1315. X    case ANY:
  1316. X        count = strlen(scan);
  1317. X        scan += count;
  1318. X        break;
  1319. X    case EXACTLY:
  1320. X        while (*opnd == *scan) {
  1321. X            count++;
  1322. X            scan++;
  1323. X        }
  1324. X        break;
  1325. X    case ANYOF:
  1326. X        while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1327. X            count++;
  1328. X            scan++;
  1329. X        }
  1330. X        break;
  1331. X    case ANYBUT:
  1332. X        while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1333. X            count++;
  1334. X            scan++;
  1335. X        }
  1336. X        break;
  1337. X    default:        /* Oh dear.  Called inappropriately. */
  1338. X        regerror("internal foulup");
  1339. X        count = 0;    /* Best compromise. */
  1340. X        break;
  1341. X    }
  1342. X    reginput = scan;
  1343. X
  1344. X    return(count);
  1345. X}
  1346. X
  1347. X/*
  1348. X - regnext - dig the "next" pointer out of a node
  1349. X */
  1350. Xstatic char *
  1351. Xregnext(p)
  1352. Xregister char *p;
  1353. X{
  1354. X    register int offset;
  1355. X
  1356. X    if (p == ®dummy)
  1357. X        return(NULL);
  1358. X
  1359. X    offset = NEXT(p);
  1360. X    if (offset == 0)
  1361. X        return(NULL);
  1362. X
  1363. X    if (OP(p) == BACK)
  1364. X        return(p-offset);
  1365. X    else
  1366. X        return(p+offset);
  1367. X}
  1368. X
  1369. X#ifdef DEBUG
  1370. X
  1371. XSTATIC char *regprop();
  1372. X
  1373. X/*
  1374. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  1375. X */
  1376. Xvoid
  1377. Xregdump(r)
  1378. Xregexp *r;
  1379. X{
  1380. X    register char *s;
  1381. X    register char op = EXACTLY;    /* Arbitrary non-END op. */
  1382. X    register char *next;
  1383. X    extern char *strchr();
  1384. X
  1385. X
  1386. X    s = r->program + 1;
  1387. X    while (op != END) {    /* While that wasn't END last time... */
  1388. X        op = OP(s);
  1389. X        printf("%2d%s", s-r->program, regprop(s));    /* Where, what. */
  1390. X        next = regnext(s);
  1391. X        if (next == NULL)        /* Next ptr. */
  1392. X            printf("(0)");
  1393. X        else 
  1394. X            printf("(%d)", (s-r->program)+(next-s));
  1395. X        s += 3;
  1396. X        if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1397. X            /* Literal string, where present. */
  1398. X            while (*s != '\0') {
  1399. X                putchar(*s);
  1400. X                s++;
  1401. X            }
  1402. X            s++;
  1403. X        }
  1404. X        putchar('\n');
  1405. X    }
  1406. X
  1407. X    /* Header fields of interest. */
  1408. X    if (r->regstart != '\0')
  1409. X        printf("start `%c' ", r->regstart);
  1410. X    if (r->reganch)
  1411. X        printf("anchored ");
  1412. X    if (r->regmust != NULL)
  1413. X        printf("must have \"%s\"", r->regmust);
  1414. X    printf("\n");
  1415. X}
  1416. X
  1417. X/*
  1418. X - regprop - printable representation of opcode
  1419. X */
  1420. Xstatic char *
  1421. Xregprop(op)
  1422. Xchar *op;
  1423. X{
  1424. X    register char *p;
  1425. X    static char buf[50];
  1426. X
  1427. X    (void) strcpy(buf, ":");
  1428. X
  1429. X    switch (OP(op)) {
  1430. X    case BOL:
  1431. X        p = "BOL";
  1432. X        break;
  1433. X    case EOL:
  1434. X        p = "EOL";
  1435. X        break;
  1436. X    case ANY:
  1437. X        p = "ANY";
  1438. X        break;
  1439. X    case ANYOF:
  1440. X        p = "ANYOF";
  1441. X        break;
  1442. X    case ANYBUT:
  1443. X        p = "ANYBUT";
  1444. X        break;
  1445. X    case BRANCH:
  1446. X        p = "BRANCH";
  1447. X        break;
  1448. X    case EXACTLY:
  1449. X        p = "EXACTLY";
  1450. X        break;
  1451. X    case NOTHING:
  1452. X        p = "NOTHING";
  1453. X        break;
  1454. X    case BACK:
  1455. X        p = "BACK";
  1456. X        break;
  1457. X    case END:
  1458. X        p = "END";
  1459. X        break;
  1460. X    case OPEN+1:
  1461. X    case OPEN+2:
  1462. X    case OPEN+3:
  1463. X    case OPEN+4:
  1464. X    case OPEN+5:
  1465. X    case OPEN+6:
  1466. X    case OPEN+7:
  1467. X    case OPEN+8:
  1468. X    case OPEN+9:
  1469. X        sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  1470. X        p = NULL;
  1471. X        break;
  1472. X    case CLOSE+1:
  1473. X    case CLOSE+2:
  1474. X    case CLOSE+3:
  1475. X    case CLOSE+4:
  1476. X    case CLOSE+5:
  1477. X    case CLOSE+6:
  1478. X    case CLOSE+7:
  1479. X    case CLOSE+8:
  1480. X    case CLOSE+9:
  1481. X        sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  1482. X        p = NULL;
  1483. X        break;
  1484. X    case STAR:
  1485. X        p = "STAR";
  1486. X        break;
  1487. X    case PLUS:
  1488. X        p = "PLUS";
  1489. X        break;
  1490. X    default:
  1491. X        regerror("corrupted opcode");
  1492. X        break;
  1493. X    }
  1494. X    if (p != NULL)
  1495. X        (void) strcat(buf, p);
  1496. X    return(buf);
  1497. X}
  1498. X#endif
  1499. X
  1500. X/*
  1501. X * The following is provided for those people who do not have strcspn() in
  1502. X * their C libraries.  They should get off their butts and do something
  1503. X * about it; at least one public-domain implementation of those (highly
  1504. X * useful) string routines has been published on Usenet.
  1505. X */
  1506. X#ifdef STRCSPN
  1507. X/*
  1508. X * strcspn - find length of initial segment of s1 consisting entirely
  1509. X * of characters not from s2
  1510. X */
  1511. X
  1512. Xstatic int
  1513. Xstrcspn(s1, s2)
  1514. Xchar *s1;
  1515. Xchar *s2;
  1516. X{
  1517. X    register char *scan1;
  1518. X    register char *scan2;
  1519. X    register int count;
  1520. X
  1521. X    count = 0;
  1522. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1523. X        for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  1524. X            if (*scan1 == *scan2++)
  1525. X                return(count);
  1526. X        count++;
  1527. X    }
  1528. X    return(count);
  1529. X}
  1530. X#endif
  1531. END_OF_regexp.c
  1532. if test 27784 -ne `wc -c <regexp.c`; then
  1533.     echo shar: \"regexp.c\" unpacked with wrong size!
  1534. fi
  1535. # end of overwriting check
  1536. fi
  1537. if test -f regexp.h -a "${1}" != "-c" ; then 
  1538.   echo shar: Will not over-write existing file \"regexp.h\"
  1539. else
  1540. echo shar: Extracting \"regexp.h\" \(574 characters\)
  1541. sed "s/^X//" >regexp.h <<'END_OF_regexp.h'
  1542. X/*
  1543. X * Definitions etc. for regexp(3) routines.
  1544. X *
  1545. X * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
  1546. X * not the System V one.
  1547. X */
  1548. X#define NSUBEXP  10
  1549. Xtypedef struct regexp {
  1550. X    char *startp[NSUBEXP];
  1551. X    char *endp[NSUBEXP];
  1552. X    char regstart;        /* Internal use only. */
  1553. X    char reganch;        /* Internal use only. */
  1554. X    char *regmust;        /* Internal use only. */
  1555. X    int regmlen;        /* Internal use only. */
  1556. X    char program[1];    /* Unwarranted chumminess with compiler. */
  1557. X} regexp;
  1558. X
  1559. Xextern regexp *regcomp();
  1560. Xextern int regexec();
  1561. Xextern void regsub();
  1562. Xextern void regerror();
  1563. END_OF_regexp.h
  1564. if test 574 -ne `wc -c <regexp.h`; then
  1565.     echo shar: \"regexp.h\" unpacked with wrong size!
  1566. fi
  1567. # end of overwriting check
  1568. fi
  1569. if test -f regmagic.h -a "${1}" != "-c" ; then 
  1570.   echo shar: Will not over-write existing file \"regmagic.h\"
  1571. else
  1572. echo shar: Extracting \"regmagic.h\" \(153 characters\)
  1573. sed "s/^X//" >regmagic.h <<'END_OF_regmagic.h'
  1574. X/*
  1575. X * The first byte of the regexp internal "program" is actually this magic
  1576. X * number; the start node begins in the second byte.
  1577. X */
  1578. X#define    MAGIC    0234
  1579. END_OF_regmagic.h
  1580. if test 153 -ne `wc -c <regmagic.h`; then
  1581.     echo shar: \"regmagic.h\" unpacked with wrong size!
  1582. fi
  1583. # end of overwriting check
  1584. fi
  1585. if test -f trmoves.c -a "${1}" != "-c" ; then 
  1586.   echo shar: Will not over-write existing file \"trmoves.c\"
  1587. else
  1588. echo shar: Extracting \"trmoves.c\" \(20210 characters\)
  1589. sed "s/^X//" >trmoves.c <<'END_OF_trmoves.c'
  1590. X/*
  1591. X *    Copyright (c) 1986 by Ray Balogh (rabalogh@ccng.waterloo.edu)
  1592. X *
  1593. X *    Permission is granted to anyone to use this software for any
  1594. X *    purpose on any computer system, and to redistribute it freely,
  1595. X *    subject to the following restrictions:
  1596. X *
  1597. X *    1. The author is not responsible for the consequences of use of
  1598. X *    this software, no matter how awful, even if they arise
  1599. X *    from defects in it.
  1600. X *
  1601. X *    2. The origin of this software must not be misrepresented, either
  1602. X *    by explicit claim or by omission.
  1603. X *
  1604. X *    3. Altered versions must be plainly marked as such, and must not
  1605. X *    be misrepresented as being the original software.
  1606. X *
  1607. X */
  1608. X
  1609. X/*  The following copyright notice appears in the chess program from which
  1610. X *  legal move generation code was derived:
  1611. X *
  1612. X         C source for CHESS               Rev. 3-10-87
  1613. X       Written by John Stanback (hplabs!hpfcla!hpisla!hpltca!jhs)
  1614. X       Patches for BSD Unix by Rich Salz (rs@mirror.TMC.COM) - 5/3/87
  1615. X *
  1616. X *
  1617. X ****************************************************************************
  1618. X */
  1619. X
  1620. X
  1621. X#include <stdio.h>
  1622. X
  1623. X#define true 1
  1624. X#define false 0
  1625. X#define neutral 0
  1626. X#define white 1
  1627. X#define black 2 
  1628. X#define no_piece 0
  1629. X#define pawn 1
  1630. X#define knight 2
  1631. X#define bishop 3
  1632. X#define rook 4
  1633. X#define queen 5
  1634. X#define king 6
  1635. X#define px " PNBRQK"
  1636. X#define qx " pnbrqk"
  1637. X#define rx "12345678"
  1638. X#define cx "abcdefgh"
  1639. X#define check     0x00000001
  1640. X#define capture   0x00000002
  1641. X#define draw      0x00000004
  1642. X#define promote_n 0x00000010
  1643. X#define promote_b 0x00000020
  1644. X#define promote_r 0x00000040
  1645. X#define promote_q 0x00000080
  1646. X#define promote   (promote_n|promote_b|promote_r|promote_q)
  1647. X#define incheck   0x00000100
  1648. X#define epmask    0x00000200
  1649. X#define exact     0x00000400
  1650. X#define pwnthrt   0x00000800
  1651. X
  1652. X#define MAXMVSTR    12
  1653. X#define DUNNO        '_'
  1654. X#define ETC        '*'
  1655. X#define BADCHAR        '\004'
  1656. X
  1657. X#define PLYSIDE(ply)    (ply % 2 ? "black" : "white")
  1658. X
  1659. X
  1660. Xstruct leaf
  1661. X  {
  1662. X    int f,t;
  1663. X    unsigned int flags;
  1664. X  };
  1665. X
  1666. Xint row[64],col[64],Index[64];
  1667. Xint PieceList[3][16],PieceCnt[3];
  1668. Xint castld[3],kingmoved[3],mtl[3],pmtl[3];
  1669. Xint qrookmoved[3],krookmoved[3];
  1670. Xint PawnCnt[3][8];
  1671. Xint GameCnt,epsquare = -1;
  1672. Xunsigned int GameList[240];
  1673. Xint GamePc[240],GameClr[240];
  1674. Xint GamePiece[240],GameColor[240],GamePromote[240];
  1675. Xint value[8]={0,100,330,330,500,950,999};
  1676. Xint otherside[3]={0,2,1};
  1677. Xint map[64]=
  1678. X   {26,27,28,29,30,31,32,33,38,39,40,41,42,43,44,45,
  1679. X    50,51,52,53,54,55,56,57,62,63,64,65,66,67,68,69,
  1680. X    74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,
  1681. X    98,99,100,101,102,103,104,105,110,111,112,113,114,115,116,117};
  1682. Xint unmap[144]=
  1683. X   {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  1684. X    -1,-1,0,1,2,3,4,5,6,7,-1,-1,-1,-1,8,9,10,11,12,13,14,15,-1,-1,
  1685. X    -1,-1,16,17,18,19,20,21,22,23,-1,-1,-1,-1,24,25,26,27,28,29,30,31,-1,-1,
  1686. X    -1,-1,32,33,34,35,36,37,38,39,-1,-1,-1,-1,40,41,42,43,44,45,46,47,-1,-1,
  1687. X    -1,-1,48,49,50,51,52,53,54,55,-1,-1,-1,-1,56,57,58,59,60,61,62,63,-1,-1,
  1688. X    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
  1689. Xint board[64]=
  1690. X   {rook,knight,bishop,queen,king,bishop,knight,rook,
  1691. X    pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
  1692. X    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  1693. X    pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
  1694. X    rook,knight,bishop,queen,king,bishop,knight,rook};
  1695. Xint color[64]=
  1696. X   {white,white,white,white,white,white,white,white,
  1697. X    white,white,white,white,white,white,white,white,
  1698. X    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  1699. X    black,black,black,black,black,black,black,black,
  1700. X    black,black,black,black,black,black,black,black};
  1701. Xint sweep[7]= {false,false,false,true,true,true,false};
  1702. Xint Dstpwn[3]={0,4,6};
  1703. Xint Dstart[7]={6,4,8,4,0,0,0};
  1704. Xint Dstop[7]={7,5,15,7,3,7,7};
  1705. Xint Dir[16]={1,12,-1,-12,11,13,-11,-13,10,-10,14,-14,23,-23,25,-25};
  1706. Xint MovePnt = 0;
  1707. Xstruct leaf Moves[2000];
  1708. Xchar charmap[] = " PNBRQK";
  1709. Xint real_ep_square = -1;
  1710. X
  1711. XInitializeStats()
  1712. X{
  1713. Xregister int i,loc;
  1714. Xint l,r,c;
  1715. X
  1716. X  for (r = 0; r < 8; r++)
  1717. X    for (c = 0; c < 8; c++)
  1718. X      {
  1719. X        l = 8*r+c;
  1720. X        row[l] = r; col[l] = c;
  1721. X      }
  1722. X  for (i = 0; i < 8; i++)
  1723. X    PawnCnt[white][i] = PawnCnt[black][i] = 0;
  1724. X
  1725. X  /*epsquare = -1;*/
  1726. X  GameCnt = -1;
  1727. X  castld[white] = castld[black] = false;
  1728. X  kingmoved[white] = kingmoved[black] = 0;
  1729. X  krookmoved[white] = krookmoved[black] = 0;
  1730. X  qrookmoved[white] = qrookmoved[black] = 0;
  1731. X
  1732. X  mtl[white] = mtl[black] = pmtl[white] = pmtl[black]=0;
  1733. X  PieceCnt[white] = PieceCnt[black] = 0;
  1734. X  for (loc = 0; loc < 64; loc++)
  1735. X    if (color[loc] != neutral)
  1736. X      {
  1737. X        mtl[color[loc]] += value[board[loc]];
  1738. X        if (board[loc] == pawn)
  1739. X          {
  1740. X            pmtl[color[loc]] += value[pawn];
  1741. X            ++PawnCnt[color[loc]][col[loc]];
  1742. X          }
  1743. X        if (board[loc] == king) Index[loc] = 0;
  1744. X          else Index[loc] = ++PieceCnt[color[loc]];
  1745. X        PieceList[color[loc]][Index[loc]] = loc;
  1746. X      }
  1747. X}
  1748. X
  1749. X
  1750. XMakeMove(side,node,tempb,tempc)
  1751. Xint side,*tempc,*tempb;
  1752. Xstruct leaf *node;
  1753. X
  1754. X/*
  1755. X    Update Arrays board[], color[], and Index[] to reflect the new
  1756. X    board position obtained after making the move pointed to by
  1757. X    node.  Also update miscellaneous stuff that changes when a move
  1758. X    is made.
  1759. X*/
  1760. X    
  1761. X{
  1762. Xregister int f,t;
  1763. Xint ok,xside;
  1764. Xint prom_val;
  1765. Xint bf, bt;
  1766. X
  1767. X  xside = otherside[side];
  1768. X  epsquare = -1;
  1769. X  f = node->f; t = node->t;
  1770. X  GameList[++GameCnt] = (f<<8) + t;
  1771. X  if (f == 255 || t == 255)
  1772. X    {
  1773. X      GamePc[GameCnt] = no_piece; GameClr[GameCnt] = neutral;
  1774. X      GamePiece[GameCnt] = no_piece; GameColor[GameCnt] = neutral;
  1775. X      GamePromote[GameCnt] = no_piece;
  1776. X      castle(side,f,t,1,&ok);
  1777. X    }
  1778. X  else
  1779. X    {
  1780. X      bf = board[f]; bt = board[t];
  1781. X      *tempc = color[t]; *tempb = bt;
  1782. X      GamePc[GameCnt] = *tempb; GameClr[GameCnt] = *tempc;
  1783. X      GamePiece[GameCnt] = bf; GameColor[GameCnt] = color[f];
  1784. X      GamePromote[GameCnt] = prompiece( node->flags );
  1785. X      if (*tempc != neutral)
  1786. X        {
  1787. X          UpdatePieceList(*tempc,t,1);
  1788. X          if (*tempb == pawn) --PawnCnt[*tempc][col[t]];
  1789. X          if (bf == pawn)
  1790. X            {
  1791. X              --PawnCnt[side][col[f]];
  1792. X              ++PawnCnt[side][col[t]];
  1793. X            }
  1794. X          mtl[xside] -= value[*tempb];
  1795. X          if (*tempb == pawn) pmtl[xside] -= value[pawn];
  1796. X        }
  1797. X      if (bf == king) ++kingmoved[side];
  1798. X      if (f==0 && bf==rook || t==0 && bt==rook) ++qrookmoved[white];
  1799. X      if (f==7 && bf==rook || t==7 && bt==rook) ++krookmoved[white];
  1800. X      if (f==56 && bf==rook || t==56 && bt==rook) ++qrookmoved[black];
  1801. X      if (f==63 && bf==rook || t==63 && bt==rook) ++krookmoved[black];
  1802. X
  1803. X      color[t] = color[f]; board[t] = bf;
  1804. X      Index[t] = Index[f]; PieceList[side][Index[t]] = t;
  1805. X      color[f] = neutral; board[f] = no_piece;
  1806. X      if (board[t] == pawn)
  1807. X        if (t-f == 16) epsquare = f+8;
  1808. X        else if (f-t == 16) epsquare = f-8;
  1809. X      if (node->flags & promote)
  1810. X        {
  1811. X          prom_val = prompiece( node->flags );
  1812. X          board[t] = prom_val;
  1813. X          mtl[side] += value[prom_val] - value[pawn];
  1814. X          pmtl[side] -= value[pawn];
  1815. X        } 
  1816. X      if (node->flags & epmask) en_passant(side,xside,f,t,1);
  1817. X    }
  1818. X}
  1819. X
  1820. X
  1821. XUnmakeMove(side,node,tempb,tempc)
  1822. Xint side,*tempc,*tempb;
  1823. Xstruct leaf *node;
  1824. X
  1825. X/*
  1826. X    Take back the move pointed to by node.
  1827. X*/
  1828. X
  1829. X{
  1830. Xregister int f,t;
  1831. Xint ok,xside;
  1832. Xint prom_val;
  1833. Xint bf, bt;
  1834. X
  1835. X  xside = otherside[side];
  1836. X  epsquare = -1;
  1837. X  f = node->f; t = node->t;
  1838. X  GameCnt--;
  1839. X  if (f == 255 || t == 255) castle(side,f,t,2,&ok);
  1840. X  else
  1841. X    {
  1842. X      if (board[t] == king) --kingmoved[side];
  1843. X      bf = board[f]; bt = board[t];
  1844. X      if (f==0 && bt==rook || t==0 && bf==rook) --qrookmoved[white];
  1845. X      if (f==7 && bt==rook || t==7 && bf==rook) --krookmoved[white];
  1846. X      if (f==56 && bt==rook || t==56 && bf==rook) --qrookmoved[black];
  1847. X      if (f==63 && bt==rook || t==63 && bf==rook) --krookmoved[black];
  1848. X
  1849. X      color[f] = color[t]; board[f] = board[t];
  1850. X      Index[f] = Index[t]; PieceList[side][Index[f]] = f;
  1851. X      color[t] = *tempc; board[t] = *tempb;
  1852. X      if (*tempc != neutral)
  1853. X        {
  1854. X          UpdatePieceList(*tempc,t,2);
  1855. X          if (*tempb == pawn) ++PawnCnt[*tempc][col[t]];
  1856. X          if (board[f] == pawn)
  1857. X            {
  1858. X              --PawnCnt[side][col[t]];
  1859. X              ++PawnCnt[side][col[f]];
  1860. X            }
  1861. X          mtl[xside] += value[*tempb];
  1862. X          if (*tempb == pawn) pmtl[xside] += value[pawn];
  1863. X        }
  1864. X      if (node->flags & promote)
  1865. X        {
  1866. X          prom_val = prompiece( node->flags );
  1867. X          board[f] = pawn;
  1868. X          mtl[side] += value[pawn] - value[prom_val];
  1869. X          pmtl[side] += value[pawn];
  1870. X        } 
  1871. X      if (node->flags & epmask) en_passant(side,xside,f,t,2);
  1872. X    }
  1873. X}
  1874. X
  1875. X
  1876. Xint
  1877. Xprompiece( promflags )
  1878. Xint promflags;
  1879. X{
  1880. X    return( (promflags & promote_q) ? queen  :
  1881. X        (promflags & promote_r) ? rook   :
  1882. X        (promflags & promote_b) ? bishop :
  1883. X        (promflags & promote_n) ? knight :
  1884. X                                  no_piece
  1885. X      );
  1886. X}
  1887. X
  1888. X
  1889. XUpdatePieceList(side,loc,iop)
  1890. Xint side,loc,iop;
  1891. X
  1892. X/*
  1893. X    Array PieceList[side][indx] contains the location of all the pieces of
  1894. X    either side. Array Index[loc] contains the indx into PieceList for a
  1895. X    given square.
  1896. X*/
  1897. X
  1898. X{
  1899. Xregister int i;
  1900. X  if (iop == 1)
  1901. X    {
  1902. X      PieceCnt[side]--;
  1903. X      for (i = Index[loc]; i <= PieceCnt[side]; i++)
  1904. X        {
  1905. X          PieceList[side][i] = PieceList[side][i+1];
  1906. X          Index[PieceList[side][i]] = i;
  1907. X        }
  1908. X    }
  1909. X  else
  1910. X    {
  1911. X      PieceCnt[side]++;
  1912. X      PieceList[side][PieceCnt[side]] = loc;
  1913. X      Index[loc] = PieceCnt[side];
  1914. X    }
  1915. X}
  1916. X  
  1917. X
  1918. Xcastle(side,f,t,iop,ok)
  1919. Xint side,f,t,iop,*ok;
  1920. X{
  1921. Xint i,e,k1,k2,r1,r2,c1,c2,t0,xside;
  1922. X
  1923. X  xside = otherside[side];
  1924. X  if (side == white) e = 0; else e = 56;
  1925. X  if (f == 255)
  1926. X    {
  1927. X      /* castle king's side */
  1928. X      k1 = e+4; k2 = e+6; r1 = e+7; r2 = e+5; c1 = k1; c2 = r1;
  1929. X    }
  1930. X  else
  1931. X    {
  1932. X      /* castle queen's side */
  1933. X      k1 = e+4; k2 = e+2; r1 = e; r2 = e+3; c1 = r1; c2 = k1;
  1934. X    }
  1935. X  if (iop == 0)
  1936. X    {
  1937. X      *ok = false;
  1938. X      if (f == 255)
  1939. X    {
  1940. X      if (castld[side] || krookmoved[side] > 0 || kingmoved[side] > 0)
  1941. X          return;
  1942. X    }
  1943. X      else
  1944. X    {
  1945. X      if (castld[side] || qrookmoved[side] > 0 || kingmoved[side] > 0)
  1946. X          return;
  1947. X    }
  1948. X      if (board[k1] == king && board[r1] == rook)
  1949. X    {
  1950. X      *ok = true;
  1951. X      for (i = c1; i <= c2; i++)
  1952. X        if (isincheck(side,i)) {*ok = false; break;}
  1953. X      if (*ok)
  1954. X          for (i = c1+1; i < c2; i++)
  1955. X        if (color[i] != neutral) {*ok = false; break;}
  1956. X    }
  1957. X    }
  1958. X  else
  1959. X    {
  1960. X      if (iop == 1) castld[side] = true; else castld[side] = false;
  1961. X      if (iop == 2)
  1962. X        {
  1963. X          t0 = k1; k1 = k2; k2 = t0;
  1964. X          t0 = r1; r1 = r2; r2 = t0;
  1965. X        }
  1966. X      board[k2] = king; color[k2] = side; Index[k2] = 0;
  1967. X      board[k1] = no_piece; color[k1] = neutral;
  1968. X      board[r2] = rook; color[r2] = side; Index[r2] = Index[r1];
  1969. X      board[r1] = no_piece; color[r1] = neutral;
  1970. X      PieceList[side][Index[k2]] = k2;
  1971. X      PieceList[side][Index[r2]] = r2;
  1972. X    }
  1973. X}
  1974. X
  1975. X
  1976. Xen_passant(side,xside,f,t,iop)
  1977. Xint side,f,t,iop;
  1978. X{
  1979. Xint l;
  1980. X  if (t > f) l = t-8; else l = t+8;
  1981. X  if (iop == 1)
  1982. X    {
  1983. X      board[l] = no_piece; color[l] = neutral;
  1984. X    }
  1985. X  else 
  1986. X    {
  1987. X      board[l] = pawn; color[l] = xside;
  1988. X    }
  1989. X  InitializeStats();
  1990. X}
  1991. X
  1992. Xint
  1993. Xisincheck(side,kingloc)
  1994. Xint side,kingloc;
  1995. X
  1996. X/*
  1997. X    Determine if king is in check (efficiently).
  1998. X*/
  1999. X
  2000. X{
  2001. X  register int u, d, m, j, loc;
  2002. X  int co, ro;
  2003. X  int xside;
  2004. X  int stop;
  2005. X  int m0;
  2006. X  int piece;
  2007. X  xside = otherside[side];
  2008. X  /*kingloc = PieceList[side][0];*/
  2009. X  co = col[kingloc]; ro = row[kingloc];
  2010. X  /* check for pawn checks */
  2011. X  if ( side == white ) {
  2012. X      if ( ro < 6 ) {
  2013. X      if ( co > 0 && color[kingloc+7] == xside && board[kingloc+7] == pawn )
  2014. X          return( true );
  2015. X      if ( co < 7 && color[kingloc+9] == xside && board[kingloc+9] == pawn )
  2016. X          return( true );
  2017. X      }
  2018. X  } else {
  2019. X      if ( ro > 1 ) {
  2020. X      if ( co < 7 && color[kingloc-7] == xside && board[kingloc-7] == pawn )
  2021. X          return( true );
  2022. X      if ( co > 0 && color[kingloc-9] == xside && board[kingloc-9] == pawn )
  2023. X          return( true );
  2024. X      }
  2025. X  }
  2026. X  /* check for knight checks */
  2027. X  m0 = map[kingloc]; stop = Dstop[knight];
  2028. X  for ( j = Dstart[knight]; j <= stop; j++ ) {
  2029. X      if ( (loc = unmap[m0+Dir[j]]) < 0 ) continue;
  2030. X      if ( board[loc] == knight && color[loc] == xside )
  2031. X      return( true );
  2032. X  }
  2033. X  /* check for bishop, rook and queen checks */
  2034. X  for ( piece = bishop; piece <= rook; piece+=(rook-bishop) )
  2035. X    {
  2036. X      stop = Dstop[piece];
  2037. X      for (j = Dstart[piece]; j <= stop; j++)
  2038. X    {
  2039. X      d = Dir[j]; m = m0+d; u = unmap[m];
  2040. X      while (u >= 0)
  2041. X        {
  2042. X          if (color[u] == neutral)
  2043. X        {
  2044. X          m += d; u = unmap[m];
  2045. X        }
  2046. X          else
  2047. X            {
  2048. X          if ( (board[u] == piece || board[u] == queen)
  2049. X              && color[u] == xside ) return( true );
  2050. X          u = -1;
  2051. X            }
  2052. X        }
  2053. X    }
  2054. X    }
  2055. X  return( false );
  2056. X}
  2057. X
  2058. X
  2059. XLinkMove(f,t,side,promoteto)
  2060. Xint f,t,side,promoteto;
  2061. X{
  2062. X
  2063. X/*
  2064. X    Add a move to the tree.
  2065. X*/
  2066. X
  2067. Xstruct leaf *node;
  2068. X
  2069. Xstruct leaf tnode;
  2070. Xint tempb, tempc;
  2071. X
  2072. X  if ( !(f == 255 || t == 255) ) {
  2073. X      /* Don't bother to link the move if the king is in check afterwards;
  2074. X     ie. it is really illegal */
  2075. X      tnode.f = f; tnode.t = t;
  2076. X      tnode.flags = 0;
  2077. X      MakeMove(side,&tnode,&tempb,&tempc);
  2078. X      if (isincheck(side,PieceList[side][0]))
  2079. X    {
  2080. X      UnmakeMove(side,&tnode,&tempb,&tempc);
  2081. X      return;
  2082. X    }
  2083. X      else
  2084. X      UnmakeMove(side,&tnode,&tempb,&tempc);
  2085. X  }
  2086. X  
  2087. X  node = &Moves[MovePnt];
  2088. X  ++MovePnt;
  2089. X  node->flags = 0;
  2090. X  node->f = f; node->t = t;
  2091. X
  2092. X  if ( !(f == 255 || t == 255) )
  2093. X    {
  2094. X      if (color[t] != neutral)
  2095. X        {
  2096. X          node->flags |= capture;
  2097. X        }
  2098. X      if (board[f] == pawn)
  2099. X        {
  2100. X          if (row[t] == 0 || row[t] == 7) node->flags |= promoteto;
  2101. X          else if (t == real_ep_square) node->flags |= epmask;
  2102. X        }
  2103. X    }
  2104. X}
  2105. X
  2106. X
  2107. XGenMoves(loc,side,xside)
  2108. Xint loc,side,xside;
  2109. X
  2110. X/*
  2111. X     Generate moves for a piece. The from square is mapped onto a 12 by 
  2112. X     12 board and offsets (taken from array Dir[]) are added to the 
  2113. X     mapped location. Array unmap[] maps the move back onto array 
  2114. X     board[] (yielding a value of -1 if the to square is off the board). 
  2115. X     This process is repeated for bishops, rooks, and queens until a 
  2116. X     piece is encountered or the the move falls off the board. Legal 
  2117. X     moves are then linked into the tree. 
  2118. X*/
  2119. X    
  2120. X{
  2121. Xregister int m,u,d;
  2122. Xint i,m0,piece; 
  2123. X
  2124. X  piece = board[loc]; m0 = map[loc];
  2125. X
  2126. X  if (sweep[piece])
  2127. X    {
  2128. X      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
  2129. X        {
  2130. X          d = Dir[i]; m = m0+d; u = unmap[m];
  2131. X          while (u >= 0)
  2132. X            if (color[u] == neutral)
  2133. X              {
  2134. X                LinkMove(loc,u,side,no_piece);
  2135. X                m += d; u = unmap[m];
  2136. X              }
  2137. X            else if (color[u] == xside)
  2138. X              {
  2139. X                LinkMove(loc,u,side,no_piece);
  2140. X                u = -1;
  2141. X              }
  2142. X            else u = -1;
  2143. X        }
  2144. X    }
  2145. X  else if (piece == pawn)
  2146. X    {
  2147. X      if (side == white && color[loc+8] == neutral)
  2148. X        {
  2149. X          if (row[loc] == 6)
  2150. X        {
  2151. X          LinkMove(loc,loc+8,side,promote_q);
  2152. X          LinkMove(loc,loc+8,side,promote_r);
  2153. X          LinkMove(loc,loc+8,side,promote_b);
  2154. X          LinkMove(loc,loc+8,side,promote_n);
  2155. X        }
  2156. X      else
  2157. X          LinkMove(loc,loc+8,side,no_piece);
  2158. X          if (row[loc] == 1)
  2159. X            if (color[loc+16] == neutral)
  2160. X              LinkMove(loc,loc+16,side,no_piece);
  2161. X        }
  2162. X      else if (side == black && color[loc-8] == neutral)
  2163. X        {
  2164. X          if (row[loc] == 1)
  2165. X        {
  2166. X          LinkMove(loc,loc-8,side,promote_q);
  2167. X          LinkMove(loc,loc-8,side,promote_r);
  2168. X          LinkMove(loc,loc-8,side,promote_b);
  2169. X          LinkMove(loc,loc-8,side,promote_n);
  2170. X        }
  2171. X      else
  2172. X          LinkMove(loc,loc-8,side,no_piece);
  2173. X          if (row[loc] == 6)
  2174. X            if (color[loc-16] == neutral)
  2175. X              LinkMove(loc,loc-16,side,no_piece);
  2176. X        }
  2177. X      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
  2178. X        if ((u = unmap[m0+Dir[i]]) >= 0)
  2179. X          if (color[u] == xside || u == real_ep_square)
  2180. X        if (side==white && row[loc]==6 || side==black && row[loc]==1)
  2181. X          {
  2182. X        LinkMove(loc,u,side,promote_q);
  2183. X        LinkMove(loc,u,side,promote_r);
  2184. X        LinkMove(loc,u,side,promote_b);
  2185. X        LinkMove(loc,u,side,promote_n);
  2186. X          }
  2187. X        else
  2188. X        LinkMove(loc,u,side,no_piece);
  2189. X    }
  2190. X  else
  2191. X    {
  2192. X      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
  2193. X        if ((u = unmap[m0+Dir[i]]) >= 0)
  2194. X          if (color[u] != side)
  2195. X            LinkMove(loc,u,side,no_piece);
  2196. X    }
  2197. X}
  2198. X
  2199. X
  2200. X
  2201. XMoveList(side)
  2202. Xint side;
  2203. X
  2204. X/*
  2205. X    Fill the array Moves[] with all available moves for side to
  2206. X    play. Array MovePnt contains the index into Moves[].
  2207. X*/
  2208. X    
  2209. X{
  2210. Xregister int i;
  2211. Xint ok,xside;
  2212. Xstatic int initted = false;
  2213. X
  2214. X  if ( !initted ) {
  2215. X      InitializeStats();
  2216. X      initted = true;
  2217. X  }
  2218. X
  2219. X  MovePnt = 0;
  2220. X  xside = otherside[side];
  2221. X  Dstart[pawn] = Dstpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
  2222. X
  2223. X  for (i = 0; i <= PieceCnt[side]; i++)
  2224. X    GenMoves(PieceList[side][i],side,xside);
  2225. X
  2226. X  castle(side,255,0,0,&ok);
  2227. X  if (ok) LinkMove(255,0,side,no_piece);
  2228. X  castle(side,0,255,0,&ok);
  2229. X  if (ok) LinkMove(0,255,side,no_piece);
  2230. X
  2231. X}
  2232. X
  2233. X
  2234. XToAlgNot( form1, form2, form3, node, side )
  2235. Xchar form1[], form2[], form3[];
  2236. Xstruct leaf *node;
  2237. X{
  2238. X    int f, t, fr, tr;
  2239. X    char ff, tf, piece, cap;
  2240. X    char prom;
  2241. X
  2242. X    f = node->f;  t = node->t;
  2243. X    if ( f == 255 ) {        /* castle king's side */
  2244. X    ff = 'e'; tf = 'g';
  2245. X    fr = tr = (side == white) ? 1 : 8;
  2246. X    cap = '-';
  2247. X    piece = 'K';
  2248. X    } else if ( t == 255 ) {    /* castle queen's side */
  2249. X    ff = 'e'; tf = 'c';
  2250. X    fr = tr = (side == white) ? 1 : 8;
  2251. X    cap = '-';
  2252. X    piece = 'K';
  2253. X    } else {
  2254. X    ff = col[f] + 'a'; tf = col[t] + 'a';
  2255. X    fr = row[f] + 1; tr = row[t] + 1;
  2256. X    cap = node->flags&(capture|epmask) ? ':' : '-';
  2257. X    piece = charmap[board[f]];
  2258. X    }
  2259. X    switch ( node->flags & promote ) {
  2260. X    case promote_n: prom = 'N'; break;
  2261. X    case promote_b: prom = 'B'; break;
  2262. X    case promote_r: prom = 'R'; break;
  2263. X    case promote_q:
  2264. X    prom = 'Q';
  2265. X    sprintf( form2, "%c%c%d%c%c%d*", piece, ff, fr, cap, tf, tr );
  2266. X    break;
  2267. X    default:        prom = '*';
  2268. X    }
  2269. X    sprintf( form1, "%c%c%d%c%c%d%c*", piece, ff, fr, cap, tf, tr, prom );
  2270. X    sprintf( form3, "%c%d%c%d", ff, fr, tf, tr );
  2271. X    if ( prom != 'Q' )
  2272. X    strcpy( form2, form1 );
  2273. X}
  2274. X
  2275. X
  2276. Xint
  2277. XMvComp( incomp, reference )
  2278. Xchar *incomp, *reference;
  2279. X{
  2280. X    for ( ; *incomp == *reference || *incomp == DUNNO; incomp++, reference++ )
  2281. X    if ( *incomp == '\0' || *reference == '\0' )
  2282. X        return( true );
  2283. X    if ( *incomp == ETC ||
  2284. X        (*reference == ETC &&
  2285. X        (*incomp == '\0' || index("nbrqNBRQ",*incomp) == NULL)) )
  2286. X    return( true );
  2287. X    return( false );
  2288. X}
  2289. X
  2290. X
  2291. Xint
  2292. XDoMove(side, move, ply)
  2293. Xint side;
  2294. Xchar move[];
  2295. Xint ply;
  2296. X{
  2297. X    int i, j, n;
  2298. X    int tempb, tempc;
  2299. X    char expandp[MAXMVSTR], expand[MAXMVSTR], compact[MAXMVSTR];
  2300. X    char gexpand[MAXMVSTR], gcompact[MAXMVSTR];
  2301. X    struct leaf *gnode;
  2302. X
  2303. X
  2304. X    MoveList( side );
  2305. X
  2306. X    for ( n = 0, i = 0; i < MovePnt; i++ ) {
  2307. X    ToAlgNot( expandp, expand, compact, &Moves[i], side );
  2308. X    if ( MvComp(move,expandp) || MvComp(move,expand) ) {
  2309. X#ifdef DEBUG
  2310. X        printf( "%s,%s,%s,%s\n", move, expandp, expand, compact );
  2311. X#endif
  2312. X        strcpy( gexpand, expand );
  2313. X        strcpy( gcompact, compact );
  2314. X        gnode = &Moves[i];
  2315. X        n++;
  2316. X    }
  2317. X    }
  2318. X
  2319. X    switch ( n ) {
  2320. X    case 0:
  2321. X#ifdef VERBOSE
  2322. X    printf( "move %d, %s: illegal move (%s) -- legal moves are:\n",
  2323. X                ply/2+1, PLYSIDE(ply), move );
  2324. X    for ( i = 0; i < MovePnt; ) {
  2325. X        printf("    ");
  2326. X        for (j = 0; j < 8 && i < MovePnt; j++, i++) {
  2327. X        ToAlgNot( expandp, expand, compact, &Moves[i], side );
  2328. X        printf( "  %s", expand );
  2329. X        }
  2330. X        printf("\n");
  2331. X    }
  2332. X#else
  2333. X    printf( "illegal move\n" );
  2334. X#endif
  2335. X    return( false );
  2336. X    case 1:
  2337. X    printf( "%s\n", gcompact ); fflush( stdout );
  2338. X    MakeMove( side, gnode, &tempb, &tempc );
  2339. X    real_ep_square = epsquare;
  2340. X    return( true );
  2341. X    default:
  2342. X#ifdef VERBOSE
  2343. X    printf( "move %d, %s: ambiguous move (%s) matches:\n",
  2344. X                ply/2+1, PLYSIDE(ply), move );
  2345. X    for (i = 0; i < MovePnt;) {
  2346. X        printf("    ");
  2347. X        for (j = 0; j < 8 && i < MovePnt; j++, i++) {
  2348. X        ToAlgNot( expandp, expand, compact, &Moves[i], side );
  2349. X        if ( MvComp(move,expandp) || MvComp(move,expand) )
  2350. X            printf( "  %s\n", expand );
  2351. X        }
  2352. X        printf( "\n" );
  2353. X    }
  2354. X#else
  2355. X    printf( "ambiguous move\n" );
  2356. X#endif
  2357. X    return( false );
  2358. X    }
  2359. X}
  2360. X
  2361. X
  2362. Xtrans(move, ply)
  2363. Xchar move[];
  2364. Xint ply;
  2365. X{
  2366. X    static int side = white;
  2367. X
  2368. X    if ( !DoMove(side,move,ply) )
  2369. X    return;
  2370. X    side = otherside[side];
  2371. X}
  2372. END_OF_trmoves.c
  2373. if test 20210 -ne `wc -c <trmoves.c`; then
  2374.     echo shar: \"trmoves.c\" unpacked with wrong size!
  2375. fi
  2376. # end of overwriting check
  2377. fi
  2378. echo shar: End of shell archive.
  2379. exit 0
  2380.